<?php
namespace App\Common\Utill;



use App\Common\RedisCache\AbstractCache;

class RedisLock
{
    private $redis;
    private $timeout = 3;

    public function __construct(\Redis $redis)
    {
        $this->redis = $redis;
    }

    public function getLockCacheKey($key)
    {
        return "lock_{$key}";
    }

    /**
     * 获取锁
     * @param $key
     * @param null $timeout
     * @return bool|int|null
     */
    public function getLock($key, $timeout = NULL)
    {
        $timeout = $timeout ? $timeout : $this->timeout;
        $lockCacheKey = $this->getLockCacheKey($key);
        $expireAt = time() + $timeout;
        $isGet = (bool)$this->redis->setnx($lockCacheKey, $expireAt);
        if ($isGet) {
            return $expireAt;
        }

        while (1) {
            usleep(10);
            $time = time();
            $oldExpire = $this->redis->get($lockCacheKey);
            if ($oldExpire >= $time) {
                continue;
            }
            $newExpire = $time + $timeout;
            $expireAt = $this->redis->getset($lockCacheKey, $newExpire);
            if ($oldExpire != $expireAt) {
                continue;
            }
            $isGet = $newExpire;
            break;
        }
        return $isGet;
    }

    /**
     * 释放锁
     * @param $key
     * @param $newExpire
     * @return bool|int
     */
    public function releaseLock($key, $newExpire)
    {
        $lockCacheKey = $this->getLockCacheKey($key);
        if ($newExpire >= time()) {
            return $this->redis->del($lockCacheKey);
        }
        return true;
    }


    /**
     * 设置redis锁
     * @param $redis_key
     * @return bool
     * @throws \Exception
     */
    static function setLock($redis_key, $expire = 2)
    {
        $LiveLockRedis = AbstractCache::getClientInstance();
        $res = $LiveLockRedis->set($redis_key, 1, array('nx', 'ex'=>$expire));
        if ($res) {
            return true;
        }
        return  false;
    }

    /**
     * 删除redis锁
     * @param $redis_key
     * @throws \Exception
     */
    static function delLock($redis_key)
    {
        $liveLockRedis = AbstractCache::getClientInstance();
        $liveLockRedis->del($redis_key);
    }

}
